package cn.nr19.jian.factory

import cn.nr19.jian.J2Utils
import cn.nr19.jian.exception.TokenException
import cn.nr19.jian.token.EToken
import cn.nr19.jian.token.StrNode
import cn.nr19.jian.token.Token

/**
 * 解析基础关键词
 */
open class TokenFactory {

    fun start(code : String) : List<Token>{
        this.code = code
        val ls = ArrayList<Token>()

        // 解析 token
        var b = next()
        while(b!=null){
            // 拆分关键词 - 系统词匹配
            if (b.type == EToken.KEY) J2Utils.pTokenType(b)

            // 关键词组合
            ls.add(b)

            //J2Utils.log(b.type,b.text)
            b = next()
        }

        return ls
    }

    /**
     * EON 关键词库少很多很多！
     */
    fun startEON(code : String) : List<Token>{
        this.code = code
        val ls = ArrayList<Token>()


        // 解析 token
        var b = next()

        while(b!=null){
            // 拆分关键词 - 系统词匹配
            if (b.type == EToken.KEY) J2Utils.pTokenTypeEON(b)

            // 关键词组合
            ls.add(b)

            //J2Utils.log(b.type,b.text)
            b = next()
        }


        return ls
    }


    // 代码
    protected var code : String = ""

    // 当前计算到的位置

    protected var curPosition = 0



    /**
     * 需要一个一个 token 找的啊
     */
    protected open fun next() : Token?{
        if (curPosition >= code.length) return null


        var k = ""
        try {

            code.get(curPosition).let {char->
                k = char.toString()
                val c = char.code

                // 此位置已读取
                curPosition++

                // 0 - 32 系统字符 , 32-47 常用标点符号，48-57 0到9，58-64常用符号，65-90大写字母，91-96常用字符，97-122小写字母，123-126符号，127删除
                // 系统字符  换行  空格 √
                if (c <= 32){
                    return when(c){
                        // 换行,回车，垂直制表符
                        10,13,11 -> {
                            Token(EToken.PN,char,curPosition).let { token->
                                var b = readNextChar()
                                while (b!=null && (b.code == 10 || b.code == 11 || b.code == 13)){
                                    curPosition++
                                    token.text += char
                                    // 继续读
                                    b = readNextChar()
                                }
                                token
                            }
                        }

                        // 空格 跳过
                        32 -> next()

                        // 其他代码不处理
                        else -> throw TokenException.notChar(char,curPosition)
                    }
                }

                // 32 -47 符号  ! "  % & ' ( ) * + , - . / √  # $
                else if (c <= 47){
                    return when(c){
                        // !  不 √
                        33 -> pBu()

                        // " 双引号 和单引号一样处理
                        34 -> {
                            // 找到下一个符号，确保没有被转义！
                            J2Utils.indexOf(code,char,curPosition).let { index->
                                if (index == -1) throw TokenException.or("找不到闭合的引号",curPosition)
                                else {
                                    J2Utils.delZy(code.substring(curPosition,index)).let {
                                        Token( EToken.Str , it,curPosition).let { t->
                                            curPosition = index + 1 // 取出闭合引号
                                            t
                                        }
                                    }

                                }
                            }

                        }

                        // 单引号，不需要去转义符
                        39 -> {
                            J2Utils.indexOf(code,char,curPosition).let { index->
                                if (index == -1) throw TokenException.or("找不到闭合的引号",curPosition)
                                else {
                                    Token(EToken.j2, code.substring(curPosition,index),curPosition).let { t->
                                        curPosition = index + 1 // 取出闭合引号
                                        t
                                    }
                                }
                            }
                        }

                        // 35 #   36$

                        // % 算是算术符号了吧 独立符号
                        37 -> Token(EToken.ysf,char,curPosition)

                        // 38 & 需要两个才能连一对
                        38 -> {
                            if (readNextChar() == char) {
                                curPosition++
                                Token(EToken.qie,char,curPosition)
                            }
                            else {
                                throw TokenException.notChar(char,curPosition)
                            }

                        }

                        // 左右括号 独立字符
                        40 -> Token(EToken.zkh,char,curPosition)
                        41 -> Token(EToken.ykh,char,curPosition)

                        // * 数学运算符
                        42 -> nextYsf(Token(EToken.ysf,char,curPosition))

                        // + 加号
                        43 -> nextYsf(Token(EToken.jia,char,curPosition))

                        // , 逗号 参数结束  独立符号
                        44 -> Token(EToken.douhao,char,curPosition)

                        // - 减号
                        45 -> {
                            // ->  当冒号用  或者组成赋值符 -=
                            readNextChar().let {
                                if (it?.code == 62){
                                    Token(EToken.maohao,"->",curPosition++)
                                }else if (it?.code == 61){
                                    Token(EToken.ysf2,"-=",curPosition++)
                                }else{
                                    Token(EToken.jian,char,curPosition)
                                }
                            }

                        }

                        // - 小数点 首个字符时为分隔符
                        46 -> {
                            // for1 ..  for2 .<
                            readNextChar().let {
                                if (it == char){
                                    curPosition++
                                    Token(EToken.FOR1,"..",curPosition)
                                }
                                // .<
                                else if (it?.code == 60) {
                                    curPosition++
                                    Token(EToken.FOR2,".<",curPosition)
                                }
                                else Token(EToken.xiaoshudian,char,curPosition)
                            }

                        }

                        // / 数学运算符  两个这种符号就是注释
                        47 -> {
                            readNextChar().let {
                                //  后面跟等于 转变为赋值 /=
                                if (it?.code == 61) {
                                    curPosition++
                                    Token(EToken.ysf2,"/=",curPosition)
                                }

                                // /* 注释开始
                                else if (it?.code == 42){
                                    val zhushi = Token(EToken.zhushi,"",curPosition)

                                    curPosition++

                                    code.indexOf("*/",curPosition).let {
                                        if (it == -1) throw TokenException.inputError("注释无闭包？或无法匹配的代码",curPosition)

                                        zhushi.text = code.substring(curPosition,it)
                                        curPosition = it + 2 // */ 两个字符
                                    }

                                   zhushi
                                }

                                // 行注释 //
                                else if (it == char){
                                    curPosition++

                                    //\n \r
                                    var kn = code.indexOf("\n",curPosition)
                                    val kr = code.indexOf("\r",curPosition)
                                    if (kr != -1 && kr < kn) kn = kr
                                    if (kn == -1) kn = code.length // 最后一行

                                    // 记录注释
                                    code.substring(curPosition,kn).let {
                                        curPosition = kn  // 跳转到换行符前
                                        Token(EToken.zhushi,it,curPosition)
                                    }

                                }

                                else{
                                    Token(EToken.ysf,char,curPosition)
                                }
                            }

                        }


                        else-> throw TokenException.notChar(char,curPosition)
                    }
                }

                // 48-57 数字 0 - 9  √  需toNext()
                else if (c <= 57) {
                    return toNext(Token(EToken.INT,char,curPosition))
                }

                // 58-64 符号 :  ; < = >    没动 ? @ 。  无需
                else if (c <= 64){
                    return when(c){
                        // 冒号 独立字符
                        58 -> Token(EToken.maohao,char,curPosition)

                        // ; 分号 独立字符 当换行使用
                        59 -> Token(EToken.PN,char,curPosition) // Token(EToken.fenhao,char,curPosition)

                        // < 少于号
                        60 -> nShaoyu(Token(EToken.shaoyu,char,curPosition))

                        // = 等于
                        61 -> {
                            if (readNextChar()?.code == 61) {
                                curPosition++ // 将下一个也获取了，就再进1
                                if (readNextChar()?.code == 61) {
                                    curPosition++
                                    Token(EToken.sspd,"===",curPosition)
                                }else{
                                    Token(EToken.sspd,"==",curPosition)
                                }
                            }
                            else {
                                Token(EToken.dengyu,char,curPosition)
                            }
                        }

                        // > 大于号
                        62 -> {
                            // 还可以组成 大于等于
                            if (readNextChar()?.code == 61) {
                                curPosition++
                                Token(EToken.sspd,">=",curPosition)
                            }
                            else Token(EToken.dayu,char,curPosition)
                        }

                        // 63 ? , 64@ ,
                        else -> throw TokenException.notChar(char,curPosition)
                    }
                }

                // 65-90大写字母 91-96常用字符，97-122小写字母
                else if (c <= 90){
                    return toNext(Token(EToken.KEY,char,curPosition))
                }

                // 91-96常用字符 [ \ ] √  ^ _ '
                else if (c <= 96){
                    return when(c){
                        // [
                        91 -> Token(EToken.zzkh,char,curPosition)

                        // \
                        92 -> {
                            Token(EToken.zy,char,curPosition)
                        }

                        // ]
                        93 -> Token(EToken.yzkh,char,curPosition)

                        // _  KEY字符
                        95 -> return toNext(Token(EToken.KEY,char,curPosition))

                        // 94 ^  95 _ 96 `
                        else -> throw TokenException.notChar(char,curPosition)
                    }
                }

                // 97-122小写字母
                else if (c <= 122){
                    return toNext(Token(EToken.KEY,char,curPosition))
                }

                // 字符
                else if (c <=  127){
                    return when(c){
                        // { 左大括号  开始
                        123 -> Token(EToken.start,"{",curPosition)

                        // |  单个字符，未组成 或 ||
                        124 -> {
                            if (readNextChar() == char) {
                                curPosition++
                                Token(EToken.huo,char,curPosition)
                            }
                            else {
                                throw TokenException.notChar(char,curPosition)
                            }
                        }

                        // }  右大括号  闭合
                        125 -> Token(EToken.end,char,curPosition)

                        // 126 ~  127 DEL
                        else -> throw TokenException.notChar(char,curPosition)
                    }
                }


                // 中文
                else if (c >= J2Utils.cn_start && c <= J2Utils.cn_end){
                    return toNext(Token(EToken.KEY,char,curPosition))
                }
                else {
                    return when(c){
                        //    不间断空格 ~~ 不知道怎么来的破内容
                        160 -> next()
                        65292 -> Token(EToken.douhao,char,curPosition)
                        65293 -> Token(EToken.jian,"-",curPosition)
                        65281 -> Token(EToken.sspd,"!",curPosition)
                        65288 -> Token(EToken.zkh,"(",curPosition)
                        65289 -> Token(EToken.ykh,")",curPosition)
                        65306 -> Token(EToken.maohao,":",curPosition)

                        // 双引号
                        8220 -> {
                            // 找到下一个符号，确保没有被转义！
                            J2Utils.indexOf(code,"”".toCharArray()[0],curPosition).let { index->
                                if (index == -1) throw TokenException.or("找不到闭合的引号",curPosition)
                                else {
                                    Token(EToken.Str,
                                        J2Utils.delZy(code.substring(curPosition,index)),curPosition).let { t->
                                        curPosition = index + 1 // 取出闭合引号
                                        t }
                                }
                            }
                        }

                        else -> {
                            J2Utils.log("其他",char,char.code)
                            null
                        }

                    }

                }
            }


        }catch (e : StringIndexOutOfBoundsException){
            e.printStackTrace()
            J2Utils.log("end",curPosition,code.length)
            // 省的判断是否是到最后
            return null
        }

    }

    // 感叹号处理
    private fun pBu() : Token{

        // 属于算术判断字  !=  , 61是等于
        readNextChar()?.code?.let {
            when(it){
                // =
                61 -> {
                    curPosition++ // 将下一个也获取了，就再进1
                    if (readNextChar()?.code == 61) {
                        curPosition++
                        return Token(EToken.sspd,"!==",curPosition)
                    }else{
                        return Token(EToken.sspd,"!=",curPosition)
                    }
                }

                // !is
                105 -> {
                    // 先进1  ，方便取 i 后面的char
                    curPosition++
                    if (readNextChar()?.code == 115) {
                        curPosition++
                        return Token(EToken.NIS,"!is",curPosition)
                    }else{
                        // !is 不成立，位置回正
                        curPosition--
                    }
                }

                else -> {}
            }

        }


        // 若上面条件成立，就中途返回，执行不到此指令。不成立就返回 不
        return Token(EToken.sspd,"!",curPosition)


    }

    /**
     * 运算符 子处理  + -
     */
    private fun nextYsf(token: Token) : Token {
        // +=  -=  当下一个字符为等于号时

        // 下一个字符必须为等于号
        readNextChar()?.let {
            if (it.code == 61){
                curPosition ++
                token.text += "="
                token.type = EToken.ysf2
            }
        }

        return token
    }

    // 少于号进一步处理
    private fun nShaoyu(token: Token) :Token{

        // 等于号  <=
        if (readNextChar()?.code == 61) {
            curPosition++
            return Token(EToken.sspd,"<=",curPosition)
        }

        // <js>xxx</js>
        listOf("简","e2","js","布局","jian","e3","ex").forEach {en->
            if (code.indexOf("${en}>",curPosition,true) == curPosition){
                J2Utils.indexOfCode(code,"</${en}>",curPosition).let { index->
                    if (index == -1) throw TokenException.or("找不到闭合符号",curPosition)
                    else {
                        val type = when(en){
                            "js"-> EToken.js
                            "ex" -> EToken.ex
                            "e2" -> EToken.e2
                            "布局" -> EToken.layout
                            else -> EToken.j2 // 简
                        }

                        return Token(type,code.substring(curPosition + ("${en}>".length),index),curPosition).let { t->
                            curPosition = index + "</${en}>".length
                            t
                        }
                    }
                }
            }
        }



        return token

    }

    private fun toNext(token: Token) : Token {
        try {
            code.get(curPosition).let {char->
                val c = char.code


                // 这里是先读取哦，大部分直接回退 token 的 勿记录先读！

                // 0 - 32 系统字符 , 32-47 常用标点符号，48-57 0到9，58-64常用符号，65-90大写字母，91-96常用字符，97-122小写字母，123-126符号，127删除
                // 系统字符  换行  空格 √
                if (c <= 32){
                    return when(c){
                        // 换行,回车，垂直制表符，空格，都表示这个token结束了
                        10,13,11,32 -> token

                        // 其他代码不处理
                        else -> throw TokenException.notChar(char,curPosition)
                    }
                }

                // 32 -47 符号 特别处理小数点
                else if (c <= 47){
                    if (c == 46){
                        if (token.type == EToken.INT){
                            curPosition++
                            token.type = EToken.DOUBLE
                            token.text += "."
                            // 再下一个必须为数字才可组成小数
                            readNextChar().let {
                                if (it != null){
                                    // 若是数字就成立  不是就不成立
                                    if (it.code in 48..57){
                                        // 既然读了，那就也加进去
                                        curPosition++
                                        token.text += it
                                        return toNext(token)
                                    }
                                }


                            }

                            // 接着不是数字，就是输入有误
                            throw TokenException.inputError(token.text + char,curPosition)
                        }
                    }

                    return token

                }

                // 48-57 数字 0 - 9  √
                else if (c <= 57) {
                    return when(token.type){
                        EToken.INT, EToken.DOUBLE, EToken.KEY ->{
                            curPosition++
                            token.text += char
                            toNext(token)
                        }
                        else -> throw TokenException.inputError(token.text + char,curPosition)
                    }
                }

                // 58-64 符号 :  ; < = > ? @  无跟随的
                else if (c <= 64) return token


                // 65-90大写字母 91-96常用字符，97-122小写字母 。 95 _
                else if (c <= 90 || c == 95){
                    return pKey(token,char)
                }

                // 91-96常用字符 [ \ ] √  ^ _ '
                else if (c <= 96) return token

                // 97-122小写字母
                else if (c <= 122){
                    return pKey(token,char)
                }

                // 字符
                else if (c <=  127) return token

                // 中文
                else if (c >= J2Utils.cn_start && c <= J2Utils.cn_end){
                    return pKey(token,char)
                }

                // 128 以上统一当 KEY
                else {
                    return when(c){
                        // 空格
                        160 -> token

                        // 逗号
                        65292,65281,65288,65289,8220,8221,65306 -> token

                        // －
                        65293 -> token

                        else -> {
                            J2Utils.log("没有的判断",char,char.code)
                            token
                        }

                    }

                }
            }
        }catch (e : StringIndexOutOfBoundsException){
            // 已经是最后一个值了，那就返回当前 token
            return token
        }

    }

    /**
     * toNext中 大小写字母 中文 都用到同一代码
     */
    private fun pKey(token: Token, char : Char) : Token {
        // 也只有KEY跟KEY
        if (token.type == EToken.KEY){
            token.text += char
            curPosition++
            return toNext(token)
        }else{
            throw TokenException.inputError("无法组合成KEY ${token}" + char,curPosition)
        }
    }

    /**
     * 读下一个字符，不会将curPosition 进 1 ！
     */
    private fun readNextChar() : Char?{
        if (curPosition < code.length) return code.get(curPosition)
        else return null
    }


    /**
     * 拆分KEY
     */
    private fun start2(tokens : List<Token>){


    }



}